/*
 * Player.java
 *
 * Created on 28 de Agosto de 2010, 12:50
 *
 */

package intopo.evogame.partnerselection.player;

import intopo.evogame.partnerselection.Cache;
import intopo.evogame.partnerselection.chromosome.Chromosome;
import intopo.evogame.partnerselection.config.AbstractTextConfigFile;
import intopo.evogame.partnerselection.config.ParsingException;
import intopo.evogame.partnerselection.population.Node;
import intopo.game.Strategy;
import intopo.game.Game;

import java.io.IOException;
import java.util.Scanner;

/**
 * Represents a player that ages and selects partners with equal probability.
 *
 * @author <a href="mailto:plsm@ua.pt">Pedro Lopes da Silva Mariano</a>
 *
 * @version 1.0 28 de Agosto de 2010
 */
final public class PlainAgingPlayer<S extends Strategy<S>>
	extends AbstractPlayer<S, Chromosome<S>, PlainAgingPlayer<S>>
{
	/**
	 * Player's age.  Represents the number of rounds of the Evolution of
	 * Partner Selection algorithm.
	 *
	 * <p> This field is part of player's phenotype.
	 */
	protected int age;

	/**
	 * Creates a new instance of Player.
	 *
	 * <p> Field {@code probabilityCombinationVectors} is created but not initialised.  The
	 * probability and combination vectors are only initalised after all
	 * players in a population have been constructed.
	 */
	public PlainAgingPlayer (Chromosome<S> chromosome, int parentID, Node<S, Chromosome<S>, PlainAgingPlayer<S>> node, int bornTime)
		throws IOException
	{
		super (chromosome, parentID, node, bornTime);
		this.age = 0;
	}

//	PlainAgingPlayer<S> factoryClone (Chromosome<S> chromosome)
//	{
//		return new PlainAgingPlayer<S> (chromosome);
//	}

	int getAge ()
	{
		return age;
	}
	/**
	 * Return the chromosome of the offspring if this player is capable of reproducing.  If this
	 * player cannot reproduce {@code null} is returned.
	 *
	 * <p> Reproduction occurs if this player's energy has reached the reproduction threshold.  This is a global parameter that effects the behaviour of all instances of class {@code PlainAgingPlayer}.
	 * After reproducing the energy is decreased by the reproduction threshold.
	 *
	 * @return the chromosome of the offspring if this player is capable of reproducing.
	 *
	 * @throws java.io.IOException If there is an error writing the chromosome to the database.
	 */
	@Override
	public Chromosome<S> reproduction ()
		throws IOException
	{
		if (energy >= Parameters.energyReproduction) {
			this.energy -= AbstractPlayer.Parameters.energyReproduction;
			return this.chromosome.reproduce ();
		}
		else {
			return null;
		}
	}
	/**
	 * Returns {@code true} if this player dies of old age.  The death probability follows a sigmoid distribution.  Instead of computing the value of the sigmoid function, we use vector {@code Cache.sigmoid2} which contains values of a sigmoid function.  The index of the vector represents the domain value.
	 * 
	 * <p> The pseudo-random number generator is {@code Cache.supply}.
	 *
	 * @return {@code true} if thies player has died.
	 * @see Cache#sigmoid2
	 * @see Cache#supply
	 */
	@Override
	public boolean dies ()
	{
		return Cache.sigmoid2 [age] >= Cache.supply.nextInt ();
	}

	/**
	 * Play a game between this player and a set of partners.
	 *
	 * <p> Parameters {@code strategies} and {@code players} are volatile
	 * fields in class {@code EvolutionPartnerSelection}.
	 *
	 * @param strategies Auxiliary parameter to store the strategies used to compute the game outcome
	 * @param players Auxiliary parameter to store the players that are going to play the game.
	 */
	void playGame (int time, Game<S> game, Game.Strategies<S> strategies, PlainAgingPlayer[] players)
		throws IOException
	{
		age++;
		super.playGame(time, game, strategies, players);
	}

	@Override
	public String toString ()
	{
		return this.energy + " " + this.chromosome;
//		return  "\t" + this.probabilityCombinationVectors;
	}

	@Override
	public void debug ()
	{
		System.out.println ("age: " + this.age);
		super.debug ();
		System.out.print ("Neighbour set:");
		for (int i = 0; i < this.neighbours.size (); i++) {
			System.out.print (" " + i + "#" + this.neighbours.get (i).chromosome.strategy);
		}
		System.out.println ();
	}

	/**
	 * Return a factory of {@code PlainAgingPlayer<S1>} instances.
	 * @param <S1> The strategy used by {@code PlainAgingPlayer} instances.
	 * @return a factory of {@code PlainAgingPlayer<S1>} instances.
	 */
	static public <S1 extends Strategy<S1>> PlayerFactory<S1, Chromosome<S1>, PlainAgingPlayer<S1>> getFactory ()
	{
		return new PlainAgingPlayer.Factory<S1> ();
	}
	/**
	 * Private class that implements the {@code PlayerFactory} interface for class {@code PlainAgingPlayer}.
	 * <p> Classes that extend {@code AbstractPlayer} have a static method that return a factory.
	 * @param <S> The strategy used by aging players.
	 */
	static private class Factory<S extends Strategy<S>>
		implements PlayerFactory<S, Chromosome<S>, PlainAgingPlayer<S>>

	{
		@Override
		public PlainAgingPlayer<S> create (Chromosome<S> c, Node<S, Chromosome<S>, PlainAgingPlayer<S>> node, int bornTime)
			throws IOException
		{
			return new PlainAgingPlayer<S> (c, AbstractPlayer.NO_PARENT, node, bornTime);
		}

		@Override
		public PlainAgingPlayer<S> create (Chromosome<S> c, int parentID, Node<S, Chromosome<S>, PlainAgingPlayer<S>> node, int bornTime)
			throws IOException
		{
			return new PlainAgingPlayer<S> (c, parentID, node, bornTime);
		}
	}


	/**
	 * Parameters common to all {@code PlainAgingPlayer} instances.
	 */
	static public class Parameters
		extends AbstractPlayer.Parameters
	{
		/**
		 * Expected player's longevity.  In order to avoid exponential growth players can die from old age: the probability to die is governed by a sigmoid function. The tipping point of this function is given by this field.  The death event is governed by field {@code death}.
		 */
		static protected int expectedLongevity;
		
		static public void read (Scanner scanner)
			throws ParsingException
		{
			AbstractPlayer.Parameters.read (scanner);
			expectedLongevity = AbstractTextConfigFile.readInt (scanner, "expected longevity");
		}
	}
}

// Local Variables: 
// mode: flyspell-prog
// ispell-local-dictionary: "british"
// End:
